/*
 * @Author: your name
 * @Date: 2021-11-15 15:26:07
 * @LastEditTime: 2021-11-29 18:10:39
 * @LastEditors: Please set LastEditors
 * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 * @FilePath: \vue-response-analysis\src\Watcher.js
 */
import Dep from "./Dep";

var uid = 0; // id全局记录
export default class Watcher {
    constructor(target, exp, callback) {
        // console.log('我是Watcher类构造器');
        this.id = uid++;
        this.target = target;
        this.getter = parsePath(exp);
        this.callback = callback;
        this.value = this.get()
    }

    /** 在构造器被实例时和 update 更新时，都会去获取一次get */
    get() {
        /* 进入收集依赖阶段，让全局的Dep.target设置为 Watcher 本身，那么就是进入依赖的收集阶段 */
        Dep.target = this

        const obj = this.target;

        var value; // 存储this.getter(obj) 的返回值，并且返回给获取者
        // 只要能找，就一直找 -- 使用try，catch
        try {
            value = this.getter(obj);
        } finally {
            // 最终（找到或者没找到都设置为null）
            // 那个数据在读whater，那个就是target
            Dep.target = null
        }

        return value
    }

    /** 更新 */
    update() {
        this.run()
    }

    run() {
        this.getAndInvoke(this.callback)
    }

    /** 得到并且唤起 */
    getAndInvoke(cb) {
        const value = this.get()

        // 在构造器被实例时和 update 更新时，都会去获取一次get()
        // 当两次值不同时，表示数据被更新，
        if (value !== this.value || typeof value == 'object') {
            const oldValue = this.value; // his.value 更新前数据存储
            this.value = value; // this.value 更新数据
            cb.call(this.target, value, oldValue)
        }
    }
}

function parsePath(string) {
    let segments = string.split('.');
    return (obj) => {
        for (let i = 0; i < segments.length; i++) {
            if (!obj) return
            obj = obj[`${segments[i]}`]
        }
        return obj
    }
}